import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AutocompleteModule } from './autocomplete.module';
import { AutocompleteItem } from './interface';
import { AutocompleteDirective } from './autocomplete.directive';
import { InputModule } from '../input/input.module';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';

@Component({
  template: `
    <input
      lv-input
      lv-autocomplete
      [(ngModel)]="selectedValue"
      [lvAutocompleteData]="lvData"
      [lvAutocompleteWidth]="lvWidth"
      [lvAutocompleteLoading]="lvLoading"
      [lvAutocompleteShowNoData]="lvShowNoData"
      [lvAutocompletePanelClass]="lvPanelClass"
      [lvAutocompletePosition]="lvPosition"
      (lvAutocompleteInputChange)="lvInputChange()"
      (lvAutocompleteSelectedChange)="lvSelectedChange()"
      (lvAutocompleteEnterEvent)="lvEnterEvent()"
    />
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
class TestAutocompleteComponent {
  selectedValue: string;
  lvData: string[] | AutocompleteItem[] = ['test1', 'test2'];
  lvWidth: string | number;
  lvLoading: boolean = false;
  lvShowNoData: boolean = true;
  lvPanelClass: string;
  lvPosition: 'topLeft' | 'topCenter' | 'topRight' | 'bottomLeft' | 'bottomCenter' | 'bottomRight' = 'bottomLeft';
  lvInputChange() {}
  lvSelectedChange() {}
  lvEnterEvent() {}
}

describe('AutocompleteComponent', () => {
  beforeEach(
    waitForAsync(() => {
      TestBed.configureTestingModule({
        declarations: [AutocompleteDirective, TestAutocompleteComponent],
        imports: [AutocompleteModule, FormsModule, InputModule, NoopAnimationsModule],
        teardown: { destroyAfterEach: true },
      }).compileComponents();
    })
  );

  describe('render', () => {
    let component: TestAutocompleteComponent;
    let fixture: ComponentFixture<TestAutocompleteComponent>;
    let cdr: ChangeDetectorRef;

    const renderComp = fakeAsync(para => {
      for (const [key, value] of Object.entries(para)) {
        component[key] = value;
      }
      fixture.detectChanges();
      tick(500);

      const input = fixture.nativeElement.querySelector('.lv-input');

      input.focus();
      cdr.detectChanges();
      tick(500);

      input.value = 'test';
      input.dispatchEvent(new Event('input'));
      cdr.detectChanges();
      tick(500);
      cdr.detectChanges();
      tick(500);
      expect(document.body).toMatchSnapshot();
    });

    beforeEach(() => {
      fixture = TestBed.createComponent(TestAutocompleteComponent);
      component = fixture.componentInstance;
      cdr = fixture.debugElement.injector.get(ChangeDetectorRef);
    });

    // 不同弹出位置渲染
    it('with lvPosition', () => {
      renderComp({ lvPosition: 'topLeft' });
    });

    // 空面板渲染
    it('with lvShowNoData', () => {
      renderComp({ lvData: [], lvShowNoData: true });
      renderComp({ lvData: [], lvShowNoData: false });
    });

    // 加载中渲染
    it('with lvLoading', () => {
      renderComp({ lvLoading: true });
    });

    // 不同下拉面板宽度渲染
    it('with lvWidth', () => {
      renderComp({ lvWidth: '10px' });
    });
  });

  describe('work', () => {
    let component: TestAutocompleteComponent;
    let fixture: ComponentFixture<TestAutocompleteComponent>;

    beforeEach(() => {
      fixture = TestBed.createComponent(TestAutocompleteComponent);
      component = fixture.componentInstance;
      jest.spyOn(component, 'lvInputChange');
      jest.spyOn(component, 'lvSelectedChange');
      jest.spyOn(component, 'lvEnterEvent');
      fixture.autoDetectChanges();
    });

    // 正常输入并选中
    it('when input', fakeAsync(() => {
      // 输入后出来选择面板
      let input = fixture.nativeElement.querySelector('.lv-input');

      input.focus();
      fixture.detectChanges();
      tick(500);

      input.value = 'test';
      input.dispatchEvent(new Event('input'));
      tick(500);
      expect(component.lvInputChange).toBeCalled();

      // 选择后
      const item = document.querySelector('.lv-autocomplete-item');
      item.dispatchEvent(new Event('click'));
      tick(500);
      expect(component.lvSelectedChange).toBeCalled();
      input = fixture.nativeElement.querySelector('.lv-input');
      expect(input.value).toContain('test1');
    }));
  });
});
